0 追蹤者

篩檢程式

篩檢程式是在控制器動作之前和/或之後執行的物件。例如,存取控制篩檢程式可以在動作之前執行,以確保特定終端使用者被允許存取它們;內容壓縮篩檢程式可以在動作之後執行,以壓縮回應內容,然後再將其發送給終端使用者。

一個篩檢程式可能包含一個前置篩檢程式(在動作之前應用的篩選邏輯)和/或一個後置篩檢程式(在動作之後應用的邏輯)。

使用篩檢程式

篩檢程式本質上是一種特殊的行為。因此,使用篩檢程式與使用行為相同。您可以在控制器類別中宣告篩檢程式,方法是覆寫其behaviors()方法,如下所示

public function behaviors()
{
    return [
        [
            'class' => 'yii\filters\HttpCache',
            'only' => ['index', 'view'],
            'lastModified' => function ($action, $params) {
                $q = new \yii\db\Query();
                return $q->from('user')->max('updated_at');
            },
        ],
    ];
}

預設情況下,在控制器類別中宣告的篩檢程式將應用於該控制器中的所有動作。但是,您可以透過配置only屬性,明確指定篩檢程式應應用於哪些動作。在上面的範例中,HttpCache篩檢程式僅適用於indexview動作。您也可以配置except屬性,以防止某些動作被篩選。

除了控制器之外,您還可以在模組應用程式中宣告篩檢程式。當您這樣做時,篩檢程式將應用於屬於該模組或應用程式的所有控制器動作,除非您像上面描述的那樣配置篩檢程式的onlyexcept屬性。

注意:在模組或應用程式中宣告篩檢程式時,您應該在onlyexcept屬性中使用路由而不是動作 ID。這是因為僅憑動作 ID 無法完全指定模組或應用程式範圍內的動作。

當為單個動作配置多個篩檢程式時,它們將根據以下描述的規則應用

  • 前置篩選
    • 按照應用程式中宣告的篩檢程式在behaviors()中列出的順序應用。
    • 按照模組中宣告的篩檢程式在behaviors()中列出的順序應用。
    • 按照控制器中宣告的篩檢程式在behaviors()中列出的順序應用。
    • 如果任何篩檢程式取消了動作執行,則在其之後的篩檢程式(包括前置篩檢程式和後置篩檢程式)將不會被應用。
  • 如果通過前置篩選,則執行動作。
  • 後置篩選
    • 按照控制器中宣告的篩檢程式在behaviors()中列出的相反順序應用。
    • 按照模組中宣告的篩檢程式在behaviors()中列出的相反順序應用。
    • 按照應用程式中宣告的篩檢程式在behaviors()中列出的相反順序應用。

建立篩檢程式

要建立新的動作篩檢程式,請從yii\base\ActionFilter擴充,並覆寫beforeAction()和/或afterAction()方法。前者將在動作執行之前執行,而後者將在動作執行之後執行。beforeAction()的傳回值決定了是否應該執行動作。如果它是false,則此篩檢程式之後的篩檢程式將被跳過,並且動作將不會被執行。

以下範例顯示了一個記錄動作執行時間的篩檢程式

namespace app\components;

use Yii;
use yii\base\ActionFilter;

class ActionTimeFilter extends ActionFilter
{
    private $_startTime;

    public function beforeAction($action)
    {
        $this->_startTime = microtime(true);
        return parent::beforeAction($action);
    }

    public function afterAction($action, $result)
    {
        $time = microtime(true) - $this->_startTime;
        Yii::debug("Action '{$action->uniqueId}' spent $time second.");
        return parent::afterAction($action, $result);
    }
}

核心篩檢程式

Yii 提供了一組常用的篩檢程式,主要位於yii\filters命名空間下。在下面,我們將簡要介紹這些篩檢程式。

AccessControl

AccessControl 根據一組規則提供簡單的存取控制。特別是,在執行動作之前,AccessControl 將檢查列出的規則,並找到第一個與目前上下文變數(例如使用者 IP 位址、使用者登入狀態等)匹配的規則。匹配的規則將決定是允許還是拒絕執行請求的動作。如果沒有規則匹配,則存取將被拒絕。

以下範例顯示如何允許已驗證的使用者存取createupdate動作,同時拒絕所有其他使用者存取這兩個動作。

use yii\filters\AccessControl;

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::class,
            'only' => ['create', 'update'],
            'rules' => [
                // allow authenticated users
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
                // everything else is denied by default
            ],
        ],
    ];
}

有關存取控制的更多詳細資訊,請參閱授權章節。

身份驗證方法篩檢程式

身份驗證方法篩檢程式用於使用各種方法驗證使用者身份,例如HTTP 基本身份驗證OAuth 2。這些篩檢程式類別都位於yii\filters\auth命名空間下。

以下範例顯示如何使用yii\filters\auth\HttpBasicAuth,使用基於 HTTP 基本身份驗證方法的存取權杖來驗證使用者身份。請注意,為了使其正常工作,您的使用者身份類別必須實作findIdentityByAccessToken()方法。

use yii\filters\auth\HttpBasicAuth;

public function behaviors()
{
    return [
        'basicAuth' => [
            'class' => HttpBasicAuth::class,
        ],
    ];
}

身份驗證方法篩檢程式通常用於實作 RESTful API。有關更多詳細資訊,請參閱 RESTful 身份驗證章節。

ContentNegotiator

ContentNegotiator 支援回應格式協商和應用程式語言協商。它將嘗試透過檢查GET參數和Accept HTTP 標頭來確定回應格式和/或語言。

在以下範例中,ContentNegotiator 配置為支援 JSON 和 XML 回應格式,以及英語(美國)和德語語言。

use yii\filters\ContentNegotiator;
use yii\web\Response;

public function behaviors()
{
    return [
        [
            'class' => ContentNegotiator::class,
            'formats' => [
                'application/json' => Response::FORMAT_JSON,
                'application/xml' => Response::FORMAT_XML,
            ],
            'languages' => [
                'en-US',
                'de',
            ],
        ],
    ];
}

回應格式和語言通常需要在應用程式生命週期中更早地確定。因此,ContentNegotiator 的設計方式使其也可以用作啟動引導組件,除了用作篩檢程式之外。例如,您可以在應用程式配置中像下面這樣配置它

use yii\filters\ContentNegotiator;
use yii\web\Response;

[
    'bootstrap' => [
        [
            'class' => ContentNegotiator::class,
            'formats' => [
                'application/json' => Response::FORMAT_JSON,
                'application/xml' => Response::FORMAT_XML,
            ],
            'languages' => [
                'en-US',
                'de',
            ],
        ],
    ],
];

資訊:如果無法從請求中確定首選內容類型和語言,則將使用formatslanguages中列出的第一個格式和語言。

HttpCache

HttpCache 透過利用Last-ModifiedEtag HTTP 標頭來實作客戶端快取。例如,

use yii\filters\HttpCache;

public function behaviors()
{
    return [
        [
            'class' => HttpCache::class,
            'only' => ['index'],
            'lastModified' => function ($action, $params) {
                $q = new \yii\db\Query();
                return $q->from('user')->max('updated_at');
            },
        ],
    ];
}

有關使用 HttpCache 的更多詳細資訊,請參閱HTTP 快取章節。

PageCache

PageCache 實作整個頁面的伺服器端快取。在以下範例中,PageCache 應用於index動作,以快取整個頁面最多 60 秒,或直到post表格中的條目計數發生變化。它還根據選擇的應用程式語言儲存不同版本的頁面。

use yii\filters\PageCache;
use yii\caching\DbDependency;

public function behaviors()
{
    return [
        'pageCache' => [
            'class' => PageCache::class,
            'only' => ['index'],
            'duration' => 60,
            'dependency' => [
                'class' => DbDependency::class,
                'sql' => 'SELECT COUNT(*) FROM post',
            ],
            'variations' => [
                \Yii::$app->language,
            ]
        ],
    ];
}

有關使用 PageCache 的更多詳細資訊,請參閱頁面快取章節。

RateLimiter

RateLimiter 根據漏桶演算法實作速率限制演算法。它主要用於實作 RESTful API。有關使用此篩檢程式的詳細資訊,請參閱速率限制章節。

VerbFilter

VerbFilter 檢查 HTTP 請求方法是否被請求的動作允許。如果不允許,它將拋出 HTTP 405 異常。在以下範例中,宣告 VerbFilter 以指定 CRUD 動作的一組典型允許請求方法。

use yii\filters\VerbFilter;

public function behaviors()
{
    return [
        'verbs' => [
            'class' => VerbFilter::class,
            'actions' => [
                'index'  => ['get'],
                'view'   => ['get'],
                'create' => ['get', 'post'],
                'update' => ['get', 'put', 'post'],
                'delete' => ['post', 'delete'],
            ],
        ],
    ];
}

Cors

跨來源資源共享CORS是一種機制,允許從資源來源網域之外的另一個網域請求網頁上的許多資源(例如字體、JavaScript 等)。特別是,JavaScript 的 AJAX 呼叫可以使用 XMLHttpRequest 機制。根據同源安全性原則,否則 Web 瀏覽器會禁止此類「跨網域」請求。CORS 定義了一種瀏覽器和伺服器可以互動以確定是否允許跨來源請求的方式。

Cors 篩檢程式應在身份驗證/授權篩檢程式之前定義,以確保 CORS 標頭始終被發送。

use yii\filters\Cors;
use yii\helpers\ArrayHelper;

public function behaviors()
{
    return ArrayHelper::merge([
        [
            'class' => Cors::class,
        ],
    ], parent::behaviors());
}

如果您想將 CORS 篩檢程式新增到 API 中的yii\rest\ActiveController類別,也請檢查REST 控制器上的章節。

可以使用$cors屬性調整 Cors 篩選。

  • cors['Origin']:用於定義允許來源的陣列。可以是['*'](所有人)或['https://www.myserver.net', 'https://www.myotherserver.com']。預設為['*']
  • cors['Access-Control-Request-Method']:允許的動詞陣列,例如['GET', 'OPTIONS', 'HEAD']。預設為['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']
  • cors['Access-Control-Request-Headers']:允許的標頭陣列。可以是['*']所有標頭或特定標頭['X-Request-With']。預設為['*']
  • cors['Access-Control-Allow-Credentials']:定義目前請求是否可以使用憑證進行。可以是truefalsenull(未設定)。預設為null
  • cors['Access-Control-Max-Age']:定義預檢請求的生命週期。預設為86400

例如,允許來源為:https://www.myserver.net的 CORS,方法為GETHEADOPTIONS

use yii\filters\Cors;
use yii\helpers\ArrayHelper;

public function behaviors()
{
    return ArrayHelper::merge([
        [
            'class' => Cors::class,
            'cors' => [
                'Origin' => ['https://www.myserver.net'],
                'Access-Control-Request-Method' => ['GET', 'HEAD', 'OPTIONS'],
            ],
        ],
    ], parent::behaviors());
}

您可以根據每個動作覆寫預設參數來調整 CORS 標頭。例如,為login動作新增Access-Control-Allow-Credentials可以這樣完成

use yii\filters\Cors;
use yii\helpers\ArrayHelper;

public function behaviors()
{
    return ArrayHelper::merge([
        [
            'class' => Cors::class,
            'cors' => [
                'Origin' => ['https://www.myserver.net'],
                'Access-Control-Request-Method' => ['GET', 'HEAD', 'OPTIONS'],
            ],
            'actions' => [
                'login' => [
                    'Access-Control-Allow-Credentials' => true,
                ]
            ]
        ],
    ], parent::behaviors());
}

發現錯字或您認為此頁面需要改進?
在 github 上編輯它 !